package main

import "fmt"

// go的函数特点
//   - 支持**多返回值**, 且返回值可命名
//   - 支持匿名函数和闭包
//   - **函数也是一种类型，一个函数可以赋值给变量**
//   - 不支持嵌套 一个包不能有两个名字一样的函数
//   - 不支持重载
//   - 不支持默认参数

// defer 延迟调用（先进后出）: 关闭文件句柄，锁资源释放，数据库连接释放
// 异常处理: panic抛出异常，recover捕获异常。导致关键流程出现不可修复性错误的使用 panic，其他使用 error。
// 单元测试: 在包目录内，所有以_test.go为后缀名的源代码文件都是go test测试的一部分，不会被go build编译到最终的可执行文件中。
//
//	测试函数前缀为Test; 基准函数前缀为Benchmark; 示例函数前缀为Example
//	方法参数必须 t *testing.T, 其中参数t用于报告测试失败和附加的日志信息
func main() {
	sum, s1 := test01(1, 2, "sum: %d")
	s2 := test02(func() int { return 100 })
	s3 := format(func(s string, x, y int) string {
		return fmt.Sprintf(s, x, y)
	}, "%d, %d", 10, 20)
	fmt.Println(sum, s1, s2, s3)
}

// 类型相同的相邻参数，参数类型可合并；多返回值必须用括号
func test01(x, y int, s string) (int, string) {
	n := x + y
	return n, fmt.Sprintf(s, n)
}

// 函数可作为参数传递；建议将复杂签名定义为函数类型，便于阅读
func test02(fn func() int) int {
	return fn()
}

type FormatFunc func(s string, x, y int) string

func format(fn FormatFunc, s string, x, y int) string {
	return fn(s, x, y)
}
